package org.skydiveapplibrary.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;

import com.dropbox.client.DropboxAPI;
import com.dropbox.client.DropboxAPI.Config;
import com.dropbox.client.DropboxAPI.FileDownload;

public class DropBoxClient
{
	// oauth keys
	// not the best approach to storing these keys, but for an open source project, what the heck
	// username admin@skydivinglogbook.com, skydive
	private static final String CONSUMER_KEY = "fcumyczh0enwngw";
	private static final String CONSUMER_SECRET = "qth1zfxdfqwr3tw";
	// account oauth keys
	private static final String ACCOUNT_PREFERENCES_NAME = "preferences";
	private static final String ACCESS_KEY_NAME = "ACCESS_KEY";
	private static final String ACCESS_SECRET_NAME = "ACCESS_SECRET";
	
	// singleton
	private static final DropBoxClient instance = new DropBoxClient();

	// the api
	private DropboxAPI api = new DropboxAPI();
	private DropboxAPI.Config config = null;
	
	private DropBoxClient()
	{
	}
	
	public static DropBoxClient getInstance()
	{
		return instance;
	}
	
	public boolean isAuthenticated(Context context)
	{
		String key = getKey(context);
		String secret = getSecret(context);
		
		// if keys not cached, authentication required
		if (key == null || secret == null)
		{
			return false;
		}
		
		// try to authenticate tokens
		config = api.authenticateToken(key, secret, getConfig());
		// if successful authentication, return false
		if (config != null && config.authStatus == DropboxAPI.STATUS_SUCCESS)
		{
			return true;
		}
		
		// otherwise, token authentication failed
		// clear keys, return true
		clearTokens(context);
		return false;
	}
	
	public boolean authenticate(Context context, String userName, String password)
	{
		// authenticate against api
		config = api.authenticate(getConfig(), userName, password);
		// store keys
		if (config != null && config.authStatus == DropboxAPI.STATUS_SUCCESS)
		{
			// store tokens for later use
			storeTokens(context, config.accessTokenKey, config.accessTokenSecret);
			return true;
		}
		
		return false;
	}
	
	public void logout(Context context)
	{
		api.deauthenticate();
		clearTokens(context);
	}
	
	public void putFiles(String remoteFolder, File... localFiles)
	{
		// create remote folder
		api.createFolder("dropbox", remoteFolder);
		// put file
		for (File localFile: localFiles)
			api.putFile("dropbox", "/" + remoteFolder, localFile);
	}
	
	public void getFile(String remoteFolder, String remoteFileName, File localFile)
		throws IOException
	{
		// get download stream
		FileDownload fileDownload = api.getFileStream("dropbox",
				"/" + remoteFolder + "/" + remoteFileName, null);

		BufferedReader reader = null;
		BufferedWriter writer = null;
		
		try
		{
			// get reader/writer
			reader = new BufferedReader(new InputStreamReader(fileDownload.is));
			writer = new BufferedWriter(new FileWriter(localFile));
			
			// copy from reader to writer
			char[] buffer = new char[4096];
			int length;
			while ((length = reader.read(buffer)) > 0)
			{
				writer.write(buffer, 0, length);
			}
		}
		finally
		{
			// close reader/writer
			if (reader != null)
				reader.close();
			if (writer != null)
				writer.close();
		}
	}
	
	private Config getConfig()
	{
		if (config == null)
		{
			config = api.getConfig(null, false);
			config.consumerKey = CONSUMER_KEY;
			config.consumerSecret = CONSUMER_SECRET;
			config.server = "api.dropbox.com";
			config.contentServer = "api-content.dropbox.com";
			config.port = 80;
		}
		return config;
	}

	private String getKey(Context context)
	{
		// get from shared preferences
		SharedPreferences preferences = context.getSharedPreferences(ACCOUNT_PREFERENCES_NAME, 0);
		return preferences.getString(ACCESS_KEY_NAME, null);
	}
	
	private String getSecret(Context context)
	{
		// get from shared preferences
		SharedPreferences preferences = context.getSharedPreferences(ACCOUNT_PREFERENCES_NAME, 0);
		return preferences.getString(ACCESS_SECRET_NAME, null);
	}
	
	private void storeTokens(Context context, String key, String secret)
	{
		// Save the access key for later
		SharedPreferences preferences = context.getSharedPreferences(ACCOUNT_PREFERENCES_NAME, 0);
		Editor edit = preferences.edit();
		edit.putString(ACCESS_KEY_NAME, key);
		edit.putString(ACCESS_SECRET_NAME, secret);
		edit.commit();
	}

	private void clearTokens(Context context)
	{
		SharedPreferences preferences = context.getSharedPreferences(ACCOUNT_PREFERENCES_NAME, 0);
		Editor edit = preferences.edit();
		edit.clear();
		edit.commit();
	}
}
